Skip to content

Commit c37c0bf

Browse files
committed
Implement tom-select for related documents
- Don't allow addition of article to it's own related - Don't show old checkbox list on edit or new document pages - Exclude restricted documents from viewing in related documents section of article page
1 parent f6ad507 commit c37c0bf

File tree

4 files changed

+117
-89
lines changed

4 files changed

+117
-89
lines changed
Lines changed: 85 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,104 @@
11
import Search from "sumo/js/search_utils";
2+
import TomSelect from "tom-select";
23

34
import "sumo/tpl/wiki-related-doc.njk";
45
import "sumo/tpl/wiki-search-results.njk";
56
import nunjucksEnv from "sumo/js/nunjucks"; // has to be loaded after templates
67

78
(function($) {
8-
var searchTimeout;
99
var locale = $('html').attr('lang');
10-
11-
var $searchField = $('#search-related');
12-
var $relatedDocsList = $('#related-docs-list');
13-
var $resultsList;
14-
15-
// To search for only wiki articles we pass w=1
1610
var search = new Search('/' + locale + '/search', {w: 1, format: 'json'});
1711

18-
function createResultsList() {
19-
$resultsList = $('<div />').addClass('input-dropdown');
20-
$searchField.after($resultsList);
21-
$resultsList.css('width', $searchField.outerWidth());
22-
$resultsList.show();
12+
document.addEventListener("DOMContentLoaded", function() {
13+
var $relatedDocsList = $('#related-docs-list');
14+
var searchInput = document.getElementById('search-related');
15+
16+
if (!searchInput) return;
2317

24-
$resultsList.on('click', '[data-pk]', function() {
25-
var $this = $(this);
18+
if (document.body.classList.contains('edit_metadata') || document.body.classList.contains('new')) {
19+
$relatedDocsList.css('display', 'none');
20+
}
2621

27-
$relatedDocsList.children('.empty-message').remove();
22+
var currentDocId = null;
23+
var $documentForm = $('form[data-document-id]');
24+
if ($documentForm.length) {
25+
currentDocId = $documentForm.data('document-id');
26+
}
2827

29-
if (!$relatedDocsList.children('[data-pk=' + $this.data('pk') + ']').length) {
30-
var context = {
31-
name: 'related_documents',
32-
doc: {
33-
id: $this.data('pk'),
34-
title: $this.text()
28+
var tomSelect = new TomSelect(searchInput, {
29+
valueField: 'id',
30+
labelField: 'title',
31+
searchField: 'title',
32+
create: false,
33+
closeAfterSelect: true,
34+
maxItems: null,
35+
plugins: {
36+
remove_button: {
37+
title: 'Remove this document'
38+
}
39+
},
40+
load: function(query, callback) {
41+
if (!query.length) return callback();
42+
43+
search.query(query, function(data) {
44+
if (!data || !data.results) {
45+
return callback();
3546
}
36-
};
37-
38-
$relatedDocsList.append(nunjucksEnv.render('wiki-related-doc.njk', context));
47+
48+
var formattedResults = data.results
49+
.filter(result => result.type === 'document')
50+
.map(function(item) {
51+
var id = item.id;
52+
if (!id && item.url) {
53+
var match = item.url.match(/\/(\d+)\//);
54+
if (match) {
55+
id = match[1];
56+
}
57+
}
58+
59+
return {
60+
id: id,
61+
title: item.title,
62+
url: item.url
63+
};
64+
})
65+
.filter(item => item.id)
66+
.filter(item => !currentDocId || item.id != currentDocId)
67+
callback(formattedResults);
68+
});
69+
},
70+
onItemAdd: function(value, item) {
71+
$relatedDocsList.children('.empty-message').remove();
72+
},
73+
render: {
74+
option: function(item, escape) {
75+
return '<div>' + escape(item.title) + '</div>';
76+
},
77+
item: function(item, escape) {
78+
var context = {
79+
name: 'related_documents',
80+
doc: {
81+
id: item.id,
82+
title: item.title
83+
}
84+
};
85+
86+
$relatedDocsList.append(nunjucksEnv.render('wiki-related-doc.njk', context));
87+
88+
return '<div>' + escape(item.title) + '</div>';
89+
},
90+
no_results: function(data, escape) {
91+
return '<div class="no-results">No documents found</div>';
92+
}
3993
}
4094
});
41-
}
42-
43-
function showResults(data) {
44-
if (!$resultsList) {
45-
createResultsList();
46-
}
47-
$resultsList.html(nunjucksEnv.render('wiki-search-results.njk', data));
48-
}
49-
50-
function handleSearch() {
51-
var $this = $(this);
52-
if ($this.val().length === 0) {
53-
window.clearTimeout(searchTimeout);
54-
if ($resultsList) {
55-
$resultsList.html('');
56-
$resultsList.hide();
95+
96+
tomSelect.on('item_remove', function(value) {
97+
$relatedDocsList.children('[data-pk=' + value + ']').remove();
98+
99+
if (!$relatedDocsList.children().length) {
100+
$relatedDocsList.html('<div class="empty-message">' + gettext('No related documents.') + '</div>');
57101
}
58-
} else if ($this.val() !== search.lastQuery) {
59-
window.clearTimeout(searchTimeout);
60-
searchTimeout = window.setTimeout(function () {
61-
search.query($this.val(), showResults);
62-
}, 200);
63-
}
64-
}
65-
66-
$searchField.on('keyup', handleSearch);
67-
68-
$searchField.on('focus', function() {
69-
if ($resultsList) {
70-
$resultsList.show();
71-
}
72-
});
73-
74-
$searchField.on('blur', function() {
75-
if ($resultsList) {
76-
// We use a timeout to ensure that you can still click on the dropdown
77-
window.setTimeout(function() {
78-
$resultsList.hide();
79-
}, 100);
80-
}
102+
});
81103
});
82104
})(jQuery);

kitsune/sumo/static/sumo/scss/components/_wiki.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33

44
@import 'tom-select/dist/scss/tom-select.default';
55

6+
// Hide the related documents list on edit metadata and new document pages
7+
body.edit_metadata #related-docs-list,
8+
body.new #related-docs-list {
9+
display: none !important;
10+
}
11+
612
figure {
713
&.linked-in-product {
814
display: flex;

kitsune/wiki/jinja2/wiki/includes/document_macros.html

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -416,23 +416,25 @@ <h2 class="sumo-page-subheading">{{ _('Related Articles') }}</h2>
416416
<div class="sumo-card-grid">
417417
<div class="scroll-wrap">
418418
{% for related in docs %}
419-
<div class="card card--article">
420-
<img class="card--icon-sm" src="{{ webpack_static('protocol/img/icons/reader-mode.svg') }}" alt="todo: title" />
421-
<div class="card--details">
422-
<h3 class="card--title">
423-
<a class="expand-this-link" href="{{ url('wiki.document', related.slug) }}"
424-
data-event-name="link_click"
425-
data-event-parameters='{"link_name": "related.kb-article"}'>
426-
{{ related.title }}
427-
</a>
428-
</h3>
429-
<div class="card--desc">
430-
<p>
431-
{{ related.html|striptags|truncate(length=150) }}
432-
</p>
433-
</div>
419+
{% if related.is_unrestricted_for(user) %}
420+
<div class="card card--article">
421+
<img class="card--icon-sm" src="{{ webpack_static('protocol/img/icons/reader-mode.svg') }}" alt="todo: title" />
422+
<div class="card--details">
423+
<h3 class="card--title">
424+
<a class="expand-this-link" href="{{ url('wiki.document', related.slug) }}"
425+
data-event-name="link_click"
426+
data-event-parameters='{"link_name": "related.kb-article"}'>
427+
{{ related.title }}
428+
</a>
429+
</h3>
430+
<div class="card--desc">
431+
<p>
432+
{{ related.html|striptags|truncate(length=150) }}
433+
</p>
434+
</div>
435+
</div>
434436
</div>
435-
</div>
437+
{% endif %}
436438
{% endfor %}
437439
</div>
438440
</div>
Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
<input type="search" autocomplete="off" id="search-related" placeholder="{{ _('Search for documents...') }}">
2-
<ul id="related-docs-list">
1+
<select id="search-related" class="tom-select-related-docs" placeholder="{{ _('Search for documents...') }}">
32
{% if related_documents.count() %}
43
{% for doc in related_documents.all() %}
5-
<li data-pk="{{ doc.pk }}">
6-
<input type="checkbox" name="{{ name }}" value="{{ doc.pk }}" checked/>
7-
{{ doc.title }}
8-
<span data-close-type="remove" class="close-button"></span>
9-
</li>
4+
<option value="{{ doc.pk }}" selected>{{ doc.title }}</option>
105
{% endfor %}
11-
{% else %}
12-
<li class="empty-message">{{ _('No related documents.') }}</li>
136
{% endif %}
14-
</ul>
7+
</select>
8+
<div id="related-docs-list">
9+
{% if not related_documents.count() %}
10+
<div class="empty-message">{{ _('No related documents.') }}</div>
11+
{% endif %}
12+
</div>

0 commit comments

Comments
 (0)